//
// Created by Fronch Darly on 2021/2/27.
//
#include <jni.h>
#include <string>
#include <lastlog.h>
#include <pthread.h>
#include "log-utils.h"
#include "controller.h"



//-------------------------------------日志回调接口---------------------------------------
/**
 * 外部接口实现
 */
class FirstNdkListenerImpl{
    private:
        jobject _listener;
        JNIEnv* _env;
        jmethodID  _showLogMethodID;
        jclass _class;

    public:
        void init() {
            _class = _env->GetObjectClass(_listener);
            _showLogMethodID = _env->GetMethodID(_class, "showLog", "(ILjava/lang/String;)V");
        }

        FirstNdkListenerImpl(JNIEnv* env, jobject listener){
            _listener = env->NewGlobalRef(listener);
            _env = env;
            init();
        }

        void onLog(int level, const char* logMsg){
            _env->CallVoidMethod(_listener, _showLogMethodID, level, _env->NewStringUTF(logMsg));
        }
};

void OnLogListerCallBack(int severity, const char *log,void* userData){
    FirstNdkListenerImpl* logger = (FirstNdkListenerImpl*)userData;
    logger->onLog(severity,log);
}
//-------------------------------------日志回调接口---------------------------------------



//-------------------------------------线程回调接口---------------------------------------
class CThreadListenerImpl{
private:
    jobject _listener;
    JNIEnv* _env;
    jmethodID  _onReceiveMethodID;
    jclass _class;

public:
    void init() {
        _class = _env->GetObjectClass(_listener);
        _onReceiveMethodID = _env->GetMethodID(_class, "receive", "(ILjava/lang/String;)V");
    }

    CThreadListenerImpl(JNIEnv* env, jobject listener){
        _listener = env->NewGlobalRef(listener);
        _env = env;
        init();
    }

    void onReceive(int level, const char* json){
        _env->CallVoidMethod(_listener, _onReceiveMethodID,level, _env->NewStringUTF(json));
    }
};

void OnCThreadListerCallBack(int severity,const char *json,void* userData){
    CThreadListenerImpl* threadListener = (CThreadListenerImpl*)userData;
    threadListener->onReceive(severity,json);
}
//-------------------------------------线程回调接口---------------------------------------


const char *PASSWORD = "pw";
long getFileSize(char* filePath);
/**
 * 初始化方法。
 * @param config 传递的初始化参数对象
 */
void NdkInit(const char* config){
    showLog("我初始化了");
}



void* normalCallBack(void* data){
    LOGI("create thread form c++ i = %d",data);
//    receive("{code:200,msg:\"成功\",data:\"线程\"}");
    pthread_exit(NULL);
}


extern "C" {
    /**
     * 对外提供的初始化方法
     * @param env
     * @param type
     * @param config_
     */
    JNIEXPORT void JNICALL
    Java_com_darly_dlndk_module_FirstNdkModule_init(JNIEnv *env, jobject type, jstring config_) {
//        const jobject *type = env->GetObjectClass(type);
        const char *config = env->GetStringUTFChars(config_, 0);
        NdkInit(config);
        showLog("我初始化了");
        showLog(config);
        LOGD("########## i = %s", config);
        env->ReleaseStringUTFChars(config_, config);
    }

    /**
     * 对外提供的注册监听方法
     * @param env
     * @param type
     * @param listener
     */
    JNIEXPORT void JNICALL
    Java_com_darly_dlndk_module_FirstNdkModule_registerListener(JNIEnv *env, jobject type,
            jobject listener) {
        // TODO
        FirstNdkListenerImpl* impl = new FirstNdkListenerImpl(env, listener);
        registerLogListener(OnLogListerCallBack, impl);
    }


    /**
     * 对外提供的测试字符串方法
     * @param env
     * @return
     */
    JNIEXPORT jstring JNICALL
    Java_com_darly_dlndk_module_FirstNdkModule_stringFromJNI(
            JNIEnv* env,
            jobject /* this */) {
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }

    /**
     * 对外提供的压缩算法
     * @param env
     * @param type
     * @param normalFilePath_
     * @param encryptFilePath_
     * @return
     */
    JNIEXPORT jboolean JNICALL
    Java_com_darly_dlndk_module_FirstNdkModule_fileEncrypt(JNIEnv *env, jobject type, jstring normalFilePath_,
            jstring encryptFilePath_) {
        const char *normalFilePath = env->GetStringUTFChars(normalFilePath_, 0);
        const char *encryptFilePath = env->GetStringUTFChars(encryptFilePath_, 0);

        int passwordLen = strlen(PASSWORD);

        showLog("要加密的文件的路径 = %s");
        showLog(normalFilePath);
        showLog("加密后的文件的路径 = %s");
        showLog(encryptFilePath);

        //读文件指针
        FILE *frp = fopen(normalFilePath, "rb");
        // 写文件指针
        FILE *fwp = fopen(encryptFilePath, "wb");

        if (frp == NULL) {
            showLog("文件不存在");
            return JNI_FALSE;
        }
        if (fwp == NULL) {
            showLog("没有写权限");
            return JNI_FALSE;
        }

        // 边读边写边加密
        int buffer;
        int index = 0;
        while ((buffer = fgetc(frp)) != EOF) {
            // write
            fputc(buffer ^ *(PASSWORD + (index % passwordLen)), fwp);  //异或的方式加密
            index++;
        }
        // 关闭文件流
        fclose(fwp);
        fclose(frp);

        showLog("文件加密成功");

        env->ReleaseStringUTFChars(normalFilePath_, normalFilePath);
        env->ReleaseStringUTFChars(encryptFilePath_, encryptFilePath);

        return JNI_TRUE;
    }

    /**
     * 注册新监听，启动线程，间隔时间返回信息。
     * @param env
     * @param thiz
     * @param listener
     * @param size
     * @param length
     */
    JNIEXPORT void JNICALL
    Java_com_darly_dlndk_module_FirstNdkModule_registerCThread(JNIEnv *env, jobject thiz,
                                                               jobject listener, jint size,
                                                               jint length){




        CThreadListenerImpl* impl = new CThreadListenerImpl(env, listener);
        registerThreadListener(OnCThreadListerCallBack, impl);
        showLog("完成registerThreadListener 注册");
        pthread_t threads[size];

        for(int i=0; i < size; i++ ){
            pthread_create(&threads[i], NULL, normalCallBack, (void *) i);
        }


        receive("{code:200,msg:\"成功\"}");
    }
}